package com.xiaoma.h5testdemo.common.dialog

import android.content.Context
import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout.LayoutParams
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.coroutineScope
import androidx.viewbinding.ViewBinding
import com.xiaoma.common.extend.appGlobalScope
import com.xiaoma.common.extend.getDrawableRes
import com.xiaoma.common.extend.isSystemDarkMode
import com.xiaoma.h5testdemo.R
import com.xiaoma.h5testdemo.common.helper.SystemBarHelper
import com.xiaoma.lib.log.KLog
import com.xiaoma.h5testdemo.common.dialog.XmImitateDialogHelper
import kotlinx.coroutines.launch
import kotlinx.parcelize.Parcelize
import java.lang.ref.WeakReference
import java.util.UUID
import java.util.concurrent.CopyOnWriteArraySet

/**
 * author: liangjingbo
 * date: 2023/12/1
 * describe:
 */
abstract class XmImitateDialog<VB : ViewBinding>(
    private val inflater: (LayoutInflater, ViewGroup, Boolean) -> VB
) {

    protected val TAG = this.javaClass.simpleName + "_XMTag"
    private lateinit var mRoot: ViewGroup
    protected lateinit var binding: VB
    private val mListeners =
        CopyOnWriteArraySet<OnDialogShowOrHiddenListener>()
    private lateinit var mHostView: ViewGroup
    private val mWho = UUID.randomUUID().toString()
    private lateinit var mHelper: XmImitateDialogHelper
    private val mDialogState = DialogState(this.javaClass.name)
    private var mLifecycle: Lifecycle? = null
    private var isShow = false
    private val mLifecycleObserver = LifecycleEventObserver { _, event ->
        if (!this::mRoot.isInitialized) return@LifecycleEventObserver
        KLog.i(TAG, "mLifecycleObserver() event:$event")
        if (event == Lifecycle.Event.ON_RESUME) {
            adapterSystemBar(mRoot.context, true)
        }
        if (event == Lifecycle.Event.ON_STOP) {
            adapterSystemBar(mRoot.context, false)
        }
    }

    fun showDialog(
        helper: XmImitateDialogHelper,
        savedInstanceState: Bundle? = null
    ) {
        try {
            mHelper = helper
            val selfId = getIdentityId()
            var dialog = helper.mDialogs[selfId]
            if (dialog != null) {
                KLog.e(TAG, "showDialog() the floating window already exists!!!")
                return
            }
            dialog = this
            helper.mDialogs[selfId] = dialog
            mDialogState.canRestore = dialog.canRestore()
            mHelper.mDialogStates.add(mDialogState)
            dialog.createView(helper.getHostView(), savedInstanceState)
            val lp = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
            helper.getHostView().addView(getRoot(), lp)
            mRoot.alpha = 1f
            mListeners.forEach {
                it.onShowDialog()
            }
            mLifecycle = mHelper.lifecycle
            appGlobalScope.launch {
                adapterSystemBar(mRoot.context, true)
                mHelper.lifecycle.addObserver(mLifecycleObserver)
            }
            isShow = true
            KLog.i(TAG, "showDialog() ")
        } catch (e: Exception) {
            e.printStackTrace()
            KLog.e(TAG, "showDialog() XM_Exception: $e")
        }
    }


    fun hideDialog() {
        try {
            if (mRoot.parent != mHostView) return
            mHostView.removeView(mRoot)
            mHelper.mDialogs.remove(getIdentityId())
            mHelper.mDialogStates.remove(mDialogState)
            if (mHelper.mDialogs.isEmpty()) {
                adapterSystemBar(mRoot.context, false)
            }
            mLifecycle?.removeObserver(mLifecycleObserver)
            isShow = false
            mListeners.forEach {
                it.onHiddenDialog()
            }
            KLog.i(TAG, "hideDialog() ")
        } catch (e: Exception) {
            KLog.e(TAG, "hideDialog() XM_Exception: $e")
            e.printStackTrace()
        }
    }


    open fun onSaveInstanceState(outState: Bundle) {
    }

    fun addDialogShowOrHiddenListener(
        listener: OnDialogShowOrHiddenListener
    ) {
        mListeners.add(listener)
    }

    fun removeDialogShowOrHiddenListener(
        listener: OnDialogShowOrHiddenListener
    ) {
        mListeners.remove(listener)
    }

    private fun createView(parent: ViewGroup, savedInstanceState: Bundle?) {
        mHostView = parent
        val context = parent.context
        mRoot = View.inflate(context, R.layout.dialog_container, null) as ViewGroup
        attachToWindow(mRoot)
        binding = inflater.invoke(LayoutInflater.from(mRoot.context), mRoot, false)
        mRoot.addView(binding.root, getParams())
        initView(savedInstanceState)
        initEvent(savedInstanceState)
    }

    private fun getRoot(): View {
        return mRoot
    }

    private fun attachToWindow(view: View) {
        view.addOnAttachStateChangeListener(
            DelegateWindowAttachListener(WeakReference(view), WeakReference(this))
        )
    }

    open fun onDetachWindow() {

    }

    open fun onAttachWindow() {

    }

    open fun getIdentityId(): String {
        return mWho
    }

    open fun initEvent(savedInstanceState: Bundle?) {}
    open fun initView(savedInstanceState: Bundle?) {}

    open fun canRestore(): Boolean = true
    abstract fun getParams(): LayoutParams
    open fun onUiModeChange() {
        if (!this::mRoot.isInitialized) return
        mRoot.background = mRoot.context.getDrawableRes(R.drawable.drawable_dialog_container_bg)
        mLifecycle?.coroutineScope?.launch {
            if (isShow) {
                adapterSystemBar(mRoot.context, true)
            }
            KLog.i(TAG, "onUiModeChange() isShow :$isShow")
        }
    }

    private fun adapterSystemBar(context: Context, show: Boolean) {
        val isSystemDarkMode = context.isSystemDarkMode()
        KLog.i(TAG, "adapterSystemBar() isSystemDarkMode:$isSystemDarkMode")
        mHelper.mWeakAct?.get()?.let {
            if (isSystemDarkMode) {
                if (show) {
                    it.window.decorView.systemUiVisibility =
                        SystemBarHelper.instance.getDialogNotLightOption()
                } else {
                    it.window.decorView.systemUiVisibility =
                        SystemBarHelper.instance.getNoLightOption()
                }
                return@let
            }
            if (show) {
                it.window.decorView.systemUiVisibility =
                    SystemBarHelper.instance.getDialogNotLightOption()
            } else {
                it.window.decorView.systemUiVisibility =
                    SystemBarHelper.instance.getLightOption()
            }
        }
    }


    interface OnDialogShowOrHiddenListener {

        fun onShowDialog() {}

        fun onHiddenDialog() {}
    }

    companion object {
        private const val ANIM_DURATION = 150L
    }
}

@Parcelize
data class DialogState(
    var className: String = "",
    var canRestore: Boolean = true
) : Parcelable

class DelegateWindowAttachListener(
    private var observerRef: WeakReference<View>?,
    private var dialogRef: WeakReference<XmImitateDialog<*>>?
) : View.OnAttachStateChangeListener {

    override fun onViewAttachedToWindow(v: View) {
        dialogRef?.get()?.onAttachWindow()
    }

    override fun onViewDetachedFromWindow(v: View) {
        try {
            observerRef?.get()?.removeOnAttachStateChangeListener(this)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        dialogRef?.get()?.onDetachWindow()
        observerRef?.clear()
        dialogRef?.clear()
    }

}